package com.sg.file.download.provider;

import com.sg.file.common.conf.FileConfiguration;
import com.sg.file.common.util.FileZip;
import com.sg.file.download.api.IFileDownloadService;
import com.sg.file.receive.provider.util.creator.PathCreator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.List;

/**
 * 本地文件下载
 * Created by asus on 2018/8/9.
 */
@Service("localFileDownload")
@Slf4j
public class LocalFileDownloadService implements IFileDownloadService {

    @Autowired
    private FileConfiguration fileConfiguration;

    private final static String ZIP_SUFFIX = "zip";

    @Override
    public void wirte(OutputStream out, String targetFilePath) throws IOException {
        zeroCopyWirte(out,targetFilePath);
    }

    @Override
    public void zipWirte(OutputStream out, List<String> filePath) throws IOException {
        //创建临时压缩文件
        StringBuilder fileNameSB = new StringBuilder(String.valueOf(System.currentTimeMillis()))
                .append(".")
                .append(ZIP_SUFFIX);
        String zipTmpFilePath = PathCreator.getTmpDirPath(fileConfiguration.getPath().getBase(),fileNameSB.toString());

        //待优化为零拷贝将需要下载的文件写入压缩文件中
        try {
            FileZip.toZipFile(zipTmpFilePath,null, (String[]) filePath.toArray());
        } catch (IOException e) {
            log.error("文件写入失败：{}",e.getMessage());
        }

        //再通过零拷贝将文件写入ServletOutputStream传递到前台，并删除临时压缩文件
        zeroCopyWirteAndRemove(out,zipTmpFilePath);
    }

    /**
     * 拷贝写入流中
     * @param out
     * @param targetFilePath
     * @param removeTragetFile 是否移除文件
     * @throws IOException
     */
    private void zeroCopyWirte(OutputStream out, String targetFilePath,boolean removeTragetFile) throws IOException {
        try (FileInputStream in = new FileInputStream(targetFilePath);
             WritableByteChannel outChannel = Channels.newChannel(out);
             //零拷贝下载
             FileChannel fileChannel = in.getChannel();) {
//                int len = 0;
//                byte[] buffer = new byte[1024];
//                while ((len = in.read(buffer)) > 0){
//                    out.write(buffer, 0, len);
//                }
            long fileSize = fileChannel.size();
            long writeLen =  fileSize/100;
            long position = 0;
            while (true) {
                position +=fileChannel.transferTo(position, writeLen, outChannel);
                if(position>=fileSize){
                    break;
                }
            }
            if(removeTragetFile) {
                //删除文件
                new File(targetFilePath).deleteOnExit();
            }
        }
    }
    /**
     * 拷贝写入流中
     * @param out
     * @param targetFilePath
     * @throws IOException
     */

    public void zeroCopyWirte(OutputStream out, String targetFilePath) throws IOException {
        zeroCopyWirte(out,targetFilePath,false);
    }


    /**
     * 拷贝写入流中，并移除文件
     * @param out
     * @param targetFilePath
     * @throws IOException
     */

    public void zeroCopyWirteAndRemove(OutputStream out, String targetFilePath) throws IOException {
        zeroCopyWirte(out,targetFilePath,true);
    }
}
